#include "cpu_usage.h"
#include <iostream>

#ifdef linux

using namespace std; 
#define _LINE_LENGTH 300 
 
 
bool GetCpuMem(float &cpu,size_t &mem, int pid,int tid = -1) 
{ 
    bool ret = false; 
    char cmdline[100]; 
    sprintf(cmdline, "ps -o %%cpu,rss,%%mem,pid,tid -mp %d", pid); 
    FILE *file; 
    file = popen(cmdline, "r"); 
    if (file == NULL)  
    { 
        printf("file == NULL\n"); 
        return false; 
    } 
 
    char line[_LINE_LENGTH]; 
    float l_cpuPrec=0; 
    int l_mem=0; 
    float l_memPrec=0; 
    int l_pid=0; 
    int l_tid=0; 
    if (fgets(line, _LINE_LENGTH, file) != NULL)  
    { 
    //  printf("1st line:%s",line); 
        if (fgets(line, _LINE_LENGTH, file) != NULL)  
        { 
    //      printf("2nd line:%s",line); 
            sscanf( line, "%f %d %f %d -", &l_cpuPrec, &l_mem, &l_memPrec, &l_pid ); 
            cpu = l_cpuPrec; 
            mem = l_mem/1024; 
            if( tid == -1 ) 
                ret = true; 
            else 
            { 
                while( fgets(line, _LINE_LENGTH, file) != NULL ) 
                { 
                    sscanf( line, "%f - - - %d", &l_cpuPrec, &l_tid ); 
    //              printf("other line:%s",line); 
    //              cout<<l_cpuPrec<<'\t'<<l_tid<<endl; 
                    if( l_tid == tid ) 
                    { 
                        printf("cpuVal is tid:%d\n",tid); 
                        cpu = l_cpuPrec; 
                        ret = true; 
                        break; 
                    } 
                } 
                if( l_tid != tid ) 
                    printf("TID not exist\n"); 
            } 
        } 
        else 
            printf("PID not exist\n"); 
    } 
    else 
        printf("Command or Parameter wrong\n"); 
    pclose(file); 
    return ret; 
} 
 
float CPUusage::GetCpuUsage()
{
	float cpu;
	size_t mem;
	int pid;
	int tid = -1;
	if(GetCpuMem(cpu,mem,pid,tid))
		return cpu;
	else
		return -1.0;
}

float CPUusage::GetMemoryUsage(){
	float cpu;
	size_t mem;
	int pid;
	int tid = -1;
	if(GetCpuMem(cpu,mem,pid,tid))
		return mem;
	else
		return -1.0;
}


#endif


#ifdef _WIN64 || _WIN32

int CProcessMonitor::GetMemoryUsage(uint64_t* mem, uint64_t* vmem)
{
	PROCESS_MEMORY_COUNTERS pmc;  
    if(GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))  
    {  
        if(mem) *mem = pmc.WorkingSetSize;  
        if(vmem) *vmem = pmc.PagefileUsage;  
        return 0;  
    }  
    return -1;  
}

CProcessMonitor::~CProcessMonitor()
{ 

	clear();
}

HANDLE CProcessMonitor::SetPID(DWORD ProcessID) { 
	clear();    //如果之前监视过另一个进程，就先关闭它的句柄
	init(); 
	return _hProcess= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, ProcessID); 
}

CProcessMonitor::CProcessMonitor()
{
	init(); 
	_processor = get_processor_number(); 
	this->m_log_status = STATUS_STOP;
	this->m_alert = false;
	this->m_cpu_threshold = 30;
	this->m_virtual_memory_threshold = uint64_t(2048) * 1024 * 1024;
	this->m_physical_memory_threshold = uint64_t(2048) * 1024 * 1024;
}

std::list<CProcessMonitor::ProcessStatus *> & CProcessMonitor::Logs(){
	return this->m_logs;
}

CProcessMonitor::CProcessMonitor(DWORD ProcessID)
{ 
	init(); 
	_processor = get_processor_number();
	this->SetPID(ProcessID);
	this->m_log_status = STATUS_STOP;
	this->m_alert = false;
	this->m_cpu_threshold = 30;
	this->m_virtual_memory_threshold = uint64_t(2048) * 1024 * 1024;
	this->m_physical_memory_threshold = uint64_t(2048) * 1024 * 1024;	
}

float CProcessMonitor::GetCpuUsage()
{
	FILETIME now;
	FILETIME creation_time;
	FILETIME exit_time;
	FILETIME kernel_time;
	FILETIME user_time;
	int64_t system_time;
	int64_t time;
	int64_t system_time_delta;
	int64_t time_delta;
	DWORD exitcode;
	float cpu = -1;
 
	if (!_hProcess) 
        return -1;
	GetSystemTimeAsFileTime(&now);
	//判断进程是否已经退出
	GetExitCodeProcess(_hProcess, &exitcode);  
	if (exitcode != STILL_ACTIVE) {
		clear();
		return -1;
	}
	//计算占用CPU的百分比
	if (!GetProcessTimes(_hProcess, &creation_time, &exit_time, &kernel_time, &user_time))
	{
		clear();
		return -1;
	}
    std::cout<<"systime "<<FileTime2UTC(&kernel_time)<<"usertime " <<FileTime2UTC(&user_time)<<std::endl;
	system_time = (FileTime2UTC(&kernel_time) + FileTime2UTC(&user_time))
		/ _processor;
	time = FileTime2UTC(&now);
	//判断是否为首次计算
	if ((_last_system_time == 0) || (_last_time == 0))
	{
		_last_system_time = system_time;
		_last_time = time;
		return -2;
	}
	system_time_delta = system_time - _last_system_time;
	time_delta = time - _last_time;
	if (time_delta == 0) {
		return -1;
	}
	cpu = (float)system_time_delta * 100 / (float)time_delta;
	_last_system_time = system_time;
	_last_time = time;
	return cpu;
}
 
CProcessMonitor::uint64_t CProcessMonitor::FileTime2UTC(const FILETIME* ftime)
{
	LARGE_INTEGER li;
 
	li.LowPart = ftime->dwLowDateTime;
	li.HighPart = ftime->dwHighDateTime;
	return li.QuadPart;
}
 
int CProcessMonitor::get_processor_number()
{
	SYSTEM_INFO info;
	GetSystemInfo(&info);
	return info.dwNumberOfProcessors;
}
int CProcessMonitor::StopLog(){
	m_mux.lock();
	m_log_status = STATUS_STOP;
	m_mux.unlock();
	return 0;
}

int CProcessMonitor::SetAlert(bool){
	m_mux.lock();	
	this->m_alert = true;
	m_mux.unlock();

	return 0;
}

int CProcessMonitor::SetAlertThreshold(int cpu, uint64_t mem,uint64_t mem2){
	m_mux.lock();	
	m_cpu_threshold = cpu;
	m_virtual_memory_threshold = mem;
	m_physical_memory_threshold = mem2;
	m_mux.unlock();

	return 0;
}

int CProcessMonitor::SetMemoryAlertNotify(OnMemoryAlert alert){
	m_mux.lock();	
	this->m_on_memory_alert = alert;
	m_mux.unlock();	

	return 0;
}

int CProcessMonitor::SetCpuAlertNotify(OnCpuAlert alert){
	m_mux.lock();	
	this->m_on_cpu_alert = alert;
	m_mux.unlock();	

	return 0;
}


void MonitorProcess(CProcessMonitor *pr,uint64_t milisecond) {

	if(pr->m_log_status == CProcessMonitor::STATUS_STARTING){
		pr->m_mux.lock();
		pr->m_log_status = CProcessMonitor::STATUS_LOGGING;
		pr->m_mux.unlock();
	}
	while(pr->m_log_status == CProcessMonitor::STATUS_LOGGING){
		Sleep(milisecond);

		SYSTEMTIME stTime;
		GetLocalTime(&stTime);
		WORD wYear = stTime.wYear;
		WORD wMonth = stTime.wMonth;
		WORD wDay = stTime.wDay;
		WORD wHour = stTime.wHour;
		WORD wMinute = stTime.wMinute;
		WORD wSecond = stTime.wSecond;
		CString m_date;
		//m_date字符串即为当前时间。如：2010年4月23日 11:12:45
		m_date.Format("%4d-%2d-%2d  %2d:%2d:%2d", wYear, wMonth, wDay,
			wHour, wMinute, wSecond);
		USES_CONVERSION;
		std::string strS(m_date); //CString-->std::string
		CProcessMonitor::ProcessStatus *p = new CProcessMonitor::ProcessStatus;
		p->time = strS;
		uint64_t vmem,pmem;
		pr->GetMemoryUsage(&pmem,&vmem);
		p->phsical_memory = pmem;
		p->virtual_memory = vmem;
		p->cpu = pr->GetCpuUsage();
		pr->m_logs.push_back(p);

		if(pr->m_alert){
			bool flag = false;
			// 物理内存大于阀值
			if(p->phsical_memory > pr->m_physical_memory_threshold){
				if(pr->m_on_memory_alert){
					pr->m_on_memory_alert(p->phsical_memory, p->virtual_memory);
				}
			}
			// 虚拟内存大于监控阀值
			if(p->virtual_memory > pr->m_virtual_memory_threshold)	{
				if(pr->m_on_memory_alert)
					pr->m_on_memory_alert(p->phsical_memory, p->virtual_memory);
			}

			// cpu大于被监控cpu
			if(p->cpu > pr->m_cpu_threshold){
				if(pr->m_on_cpu_alert){
					pr->m_on_cpu_alert(p->cpu);				
				}
			}
		}
	}
}

int CProcessMonitor::StartLog(uint64_t milisecond){
	if(m_log_status != STATUS_STOP )
		return -1;
	if(m_logs.size() > 0){
		for(auto itr = m_logs.begin();itr != m_logs.end();itr++){
			delete *itr;
		}
		m_logs.clear();
	}
	this->m_log_status = STATUS_STARTING;

	m_thread = new std::thread(MonitorProcess,this,milisecond);
	return 0;
}

#endif